/*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
**      10        20        30        40        50        60        70        80
**
** program:
**    gl-cairo-cube
**
** author:
**    Mirco "MacSlow" Mueller <macslow@bangang.de>
**
** copyright (C) Mirco Mueller, 2006/2007
**
** notes:
**    Simple example demonstrating how one could use cairo for generating
**    dynamic texture-mapping with OpenGL. Intended to be run on a composited
**    desktop (e.g. compiz, xcompmgr) with proper a OpenGL-implementation. I put
**    this program under the terms of the "GNU General Public License". If you
**    don't know what that means take a look a here...
**
**        http://www.gnu.org/licenses/licenses.html#GPL
**
*******************************************************************************/

#include <gtk/gtk.h>
#include <gtk/gtkgl.h>
#include <GL/glut.h>

#include "geometry.h"
#include "events.h"
#include "cairo-rendering.h"

GTimer *g_pTimerId = NULL;
gint g_iWidth = 1;
gint g_iHeight = 1;
cairo_t *g_pCairoContext[3];
guchar *g_pucSurfaceData[3];
gulong g_ulMilliSeconds = 0L;
Line g_lineOne;
Line g_lineTwo;

int main(int argc,
		 char **argv)
{
	GtkWidget *pWindow = NULL;
	GdkGLConfig *pGlConfig = NULL;
	GtkWidget *pDrawingArea = NULL;
	guint uiDrawHandlerId = 0;
	cairo_surface_t *pCairoSurface[2];

	g_lineOne.start.fX = 0.1f;
	g_lineOne.start.fY = 0.2f;
	g_lineOne.start.bGrowX = TRUE;
	g_lineOne.start.bGrowY = TRUE;
	g_lineOne.start.fStepX = 0.025f;
	g_lineOne.start.fStepY = 0.02f;
	g_lineOne.start.fLowerLimitX = 0.1f;
	g_lineOne.start.fUpperLimitX = 0.9f;
	g_lineOne.start.fLowerLimitY = 0.1f;
	g_lineOne.start.fUpperLimitY = 0.9f;

	g_lineOne.end.fX = 0.5f;
	g_lineOne.end.fY = 0.7f;
	g_lineOne.end.bGrowX = TRUE;
	g_lineOne.end.bGrowY = FALSE;
	g_lineOne.end.fStepX = 0.025f;
	g_lineOne.end.fStepY = 0.01f;
	g_lineOne.end.fLowerLimitX = 0.1f;
	g_lineOne.end.fUpperLimitX = 0.9f;
	g_lineOne.end.fLowerLimitY = 0.1f;
	g_lineOne.end.fUpperLimitY = 0.9f;

	g_lineTwo.start.fX = 0.75f;
	g_lineTwo.start.fY = 0.1f;
	g_lineTwo.start.bGrowX = FALSE;
	g_lineTwo.start.bGrowY = TRUE;
	g_lineTwo.start.fStepX = 0.01f;
	g_lineTwo.start.fStepY = 0.025f;
	g_lineTwo.start.fLowerLimitX = 0.1f;
	g_lineTwo.start.fUpperLimitX = 0.9f;
	g_lineTwo.start.fLowerLimitY = 0.1f;
	g_lineTwo.start.fUpperLimitY = 0.9f;

	g_lineTwo.end.fX = 0.8f;
	g_lineTwo.end.fY = 0.8f;
	g_lineTwo.end.bGrowX = FALSE;
	g_lineTwo.end.bGrowY = FALSE;
	g_lineTwo.end.fStepX = 0.01f;
	g_lineTwo.end.fStepY = 0.01f;
	g_lineTwo.end.fLowerLimitX = 0.1f;
	g_lineTwo.end.fUpperLimitX = 0.9f;
	g_lineTwo.end.fLowerLimitY = 0.1f;
	g_lineTwo.end.fUpperLimitY = 0.9f;

	/* init gtk+, GL and glut */
	gtk_init(&argc, &argv);
	gtk_gl_init(&argc, &argv);
	glutInit(&argc, argv);

	/* setup GL-context */
	pGlConfig = gdk_gl_config_new_by_mode(GDK_GL_MODE_RGB |
										  GDK_GL_MODE_ALPHA |
										  GDK_GL_MODE_DEPTH |
										  GDK_GL_MODE_DOUBLE);

	if (!pGlConfig)
	{
		g_print("Could not setup GL-context!\n");
		return 1;
	}

	/* create window and hook up event-handlers */
	pWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	if (!pWindow)
	{
		g_print("Could not create gtk+-window!\n");
		return 2;
	}

	gtk_widget_add_events(pWindow,
						  GDK_POINTER_MOTION_MASK |
							  GDK_BUTTON_PRESS_MASK |
							  GDK_BUTTON_RELEASE_MASK);

	g_signal_connect(G_OBJECT(pWindow),
					 "delete-event",
					 G_CALLBACK(delete_handler),
					 NULL);
	g_signal_connect(G_OBJECT(pWindow),
					 "button-press-event",
					 G_CALLBACK(button_handler),
					 NULL);
	g_signal_connect(G_OBJECT(pWindow),
					 "button-release-event",
					 G_CALLBACK(button_handler),
					 NULL);
	g_signal_connect(G_OBJECT(pWindow),
					 "screen-changed",
					 G_CALLBACK(screen_changed_handler),
					 NULL);
	g_signal_connect(G_OBJECT(pWindow),
					 "scroll-event",
					 G_CALLBACK(scroll_handler),
					 NULL);
	g_signal_connect(G_OBJECT(pWindow),
					 "key-press-event",
					 G_CALLBACK(key_press_handler),
					 NULL);

	pDrawingArea = gtk_drawing_area_new();
	if (!pDrawingArea)
	{
		g_print("Could not create drawing-area!\n");
		return 3;
	}

	g_iWidth = 512;
	g_iHeight = 512;
	gtk_widget_set_size_request(pDrawingArea, g_iWidth, g_iHeight);
	gtk_widget_set_gl_capability(pDrawingArea,
								 pGlConfig,
								 NULL,
								 TRUE,
								 GDK_GL_RGBA_TYPE);

	g_signal_connect_after(G_OBJECT(pDrawingArea),
						   "realize",
						   G_CALLBACK(realize_handler),
						   NULL);
	g_signal_connect(G_OBJECT(pDrawingArea),
					 "configure-event",
					 G_CALLBACK(configure_handler),
					 NULL);
	g_signal_connect(G_OBJECT(pDrawingArea),
					 "expose-event",
					 G_CALLBACK(expose_handler),
					 NULL);
	g_signal_connect(G_OBJECT(pWindow),
					 "motion-notify-event",
					 G_CALLBACK(motion_notify_handler),
					 (gpointer)pDrawingArea);

	gtk_container_add(GTK_CONTAINER(pWindow), pDrawingArea);
	gtk_widget_show(pDrawingArea);
	gtk_window_set_resizable(GTK_WINDOW(pWindow), FALSE);
	gtk_widget_set_app_paintable(pWindow, TRUE);
	gtk_window_set_decorated(GTK_WINDOW(pWindow), FALSE);
	screen_changed_handler(pWindow, NULL, NULL);
	screen_changed_handler(pDrawingArea, NULL, NULL);
	gtk_widget_realize(pWindow);
	gdk_window_set_back_pixmap(pWindow->window, NULL, FALSE);
	gtk_widget_show(pWindow);

	/* create cairo-surface/context to act as OpenGL-texture */
	g_pucSurfaceData[0] = g_malloc0(4 * g_iWidth * g_iHeight);
	g_pucSurfaceData[1] = g_malloc0(4 * g_iWidth * g_iHeight);
	g_pucSurfaceData[2] = g_malloc0(4 * g_iWidth * g_iHeight);
	if (g_pucSurfaceData[0] && g_pucSurfaceData[1] && g_pucSurfaceData[2])
	{
		pCairoSurface[0] = cairo_image_surface_create_for_data(g_pucSurfaceData[0],
															   CAIRO_FORMAT_ARGB32,
															   g_iWidth,
															   g_iHeight,
															   4 * g_iWidth);

		pCairoSurface[1] = cairo_image_surface_create_for_data(g_pucSurfaceData[1],
															   CAIRO_FORMAT_ARGB32,
															   g_iWidth,
															   g_iHeight,
															   4 * g_iWidth);

		pCairoSurface[2] = cairo_image_surface_create_for_data(g_pucSurfaceData[2],
															   CAIRO_FORMAT_ARGB32,
															   g_iWidth,
															   g_iHeight,
															   4 * g_iWidth);

		g_pCairoContext[0] = cairo_create(pCairoSurface[0]);
		g_pCairoContext[1] = cairo_create(pCairoSurface[1]);
		g_pCairoContext[2] = cairo_create(pCairoSurface[2]);
	}

	/* force a refresh-rate of 20 Hz */
	uiDrawHandlerId = g_timeout_add(50,
									(GSourceFunc)draw_handler,
									pDrawingArea);

	/* register timer used by fps-counter */
	g_pTimerId = g_timer_new();

	/* enter event-loop */
	gtk_main();

	/* clear resources before exit */
	if (g_pucSurfaceData[0])
		g_free(g_pucSurfaceData[0]);
	if (g_pucSurfaceData[1])
		g_free(g_pucSurfaceData[1]);
	if (g_pucSurfaceData[2])
		g_free(g_pucSurfaceData[2]);

	return 0;
}
